package data

import (
	"blog/model"
	"fmt"
	"html/template"
	"sync"
	"time"

	"gitee.com/xchengli/blog-lib/database"
	"gitee.com/xchengli/blog-lib/zlog"

	"github.com/gin-gonic/gin"
)

type TypeDataService struct{}

// GetAllTypes 获取所有分类
func (s *TypeDataService) GetAllTypes(ctx *gin.Context) ([]model.Type, error) {
	var types []model.Type
	db := database.GetDB()

	if err := db.Where("is_show = ?", 1).Order("sort ASC, id ASC").Find(&types).Error; err != nil {
		return nil, err
	}

	return types, nil
}

// GetTypeByID 根据ID获取分类
func (s *TypeDataService) GetTypeByID(ctx *gin.Context, id int) (*model.Type, error) {
	var typeItem model.Type
	db := database.GetDB()

	if err := db.Where("id = ? AND is_show = ?", id, 1).First(&typeItem).Error; err != nil {
		return nil, err
	}

	return &typeItem, nil
}

// GetTypesByFID 根据父分类ID获取子分类
func (s *TypeDataService) GetTypesByFID(ctx *gin.Context, fid int) ([]model.Type, error) {
	var types []model.Type
	db := database.GetDB()

	if err := db.Where("fid = ? AND is_show = ?", fid, 1).Order("sort ASC, id ASC").Find(&types).Error; err != nil {
		return nil, err
	}

	return types, nil
}

// GetMainTypes 获取主分类（fid=0）
func (s *TypeDataService) GetMainTypes(ctx *gin.Context) ([]model.Type, error) {
	return s.GetTypesByFID(ctx, 0)
}

// CreateType 创建分类
func (s *TypeDataService) CreateType(ctx *gin.Context, typeItem *model.Type) error {
	db := database.GetDB()
	return db.Create(typeItem).Error
}

// CreateTypeName 创建分类（TypeName版本）
func (s *TypeDataService) CreateTypeName(ctx *gin.Context, typeItem *model.TypeName) error {
	db := database.GetDB()
	return db.Create(typeItem).Error
}

// UpdateTypeName 更新分类（TypeName版本）
func (s *TypeDataService) UpdateTypeName(ctx *gin.Context, typeItem *model.TypeName) error {
	db := database.GetDB()
	return db.Save(typeItem).Error
}

// GetTypeNameByID 根据ID获取分类（TypeName版本）
func (s *TypeDataService) GetTypeNameByID(ctx *gin.Context, id int64) (*model.TypeName, error) {
	var typeItem model.TypeName
	db := database.GetDB()

	if err := db.Where("id = ?", id).First(&typeItem).Error; err != nil {
		return nil, err
	}

	return &typeItem, nil
}

// CheckAddFID 验证分类父级ID
func (s *TypeDataService) CheckAddFID(ctx *gin.Context, postType *model.TypeName, fid int) (bool, string) {
	return s.checkAddFID(ctx, postType, fid)
}

// CheckAddName 验证分类名称
func (s *TypeDataService) CheckAddName(ctx *gin.Context, postType *model.TypeName, name string, fid int) (bool, string) {
	return s.checkAddName(ctx, postType, name, fid)
}

// UpdateType 更新分类
func (s *TypeDataService) UpdateType(ctx *gin.Context, typeItem *model.Type) error {
	db := database.GetDB()
	return db.Save(typeItem).Error
}

// DeleteType 删除分类
func (s *TypeDataService) DeleteType(ctx *gin.Context, id int) error {
	db := database.GetDB()
	return db.Model(&model.Type{}).Where("id = ?", id).Update("is_show", 0).Error
}

// GetTypeWithChildren 获取分类及其子分类
func (s *TypeDataService) GetTypeWithChildren(ctx *gin.Context) ([]model.TypeListData, error) {
	var types []model.Type
	db := database.GetDB()

	// 获取所有分类
	if err := db.Where("is_show = ?", 1).Order("sort ASC, id ASC").Find(&types).Error; err != nil {
		return nil, err
	}

	// 构建分类树结构
	typeMap := make(map[int]*model.TypeListData)
	var result []model.TypeListData

	// 先创建所有分类的映射
	for _, t := range types {
		typeMap[t.ID] = &model.TypeListData{
			ID:        t.ID,
			Name:      t.Name,
			PostNum:   0, // 这里可以后续统计文章数量
			FID:       t.FID,
			FIDName:   "",
			ReadLevel: t.ReadLevel,
			IsShow:    t.IsShow == 1,
			Child:     []*model.TypeListData{},
		}
	}

	// 构建父子关系
	for _, t := range types {
		typeData := typeMap[t.ID]

		// 设置父分类名称
		if t.FID > 0 {
			if parent, exists := typeMap[t.FID]; exists {
				typeData.FIDName = parent.Name
			}
		}

		if t.FID == 0 {
			// 主分类
			result = append(result, *typeData)
		} else {
			// 子分类，添加到父分类的children中
			if parent, exists := typeMap[t.FID]; exists {
				parent.Child = append(parent.Child.([]*model.TypeListData), typeData)
			}
		}
	}

	return result, nil
}

// GetTypePostCount 获取分类的文章数量
func (s *TypeDataService) GetTypePostCount(ctx *gin.Context, typeID int) (int64, error) {
	var count int64
	db := database.GetDB()

	if err := db.Model(&model.Post{}).Where("post_type = ? AND is_show = ?", typeID, 1).Count(&count).Error; err != nil {
		return 0, err
	}

	return count, nil
}

// GetTypesWithPostCount 获取分类及其文章数量
func (s *TypeDataService) GetTypesWithPostCount(ctx *gin.Context) ([]model.TypeListData, error) {
	types, err := s.GetTypeWithChildren(ctx)
	if err != nil {
		return nil, err
	}

	// 为每个分类添加文章数量
	for i := range types {
		count, err := s.GetTypePostCount(ctx, types[i].ID)
		if err != nil {
			continue // 忽略错误，继续处理其他分类
		}
		types[i].PostNum = int(count)

		// 处理子分类的文章数量
		if children, ok := types[i].Child.([]*model.TypeListData); ok {
			for _, child := range children {
				childCount, err := s.GetTypePostCount(ctx, child.ID)
				if err != nil {
					continue
				}
				child.PostNum = int(childCount)
			}
		}
	}

	return types, nil
}

// GetTypeList 获取分类列表
func (s *TypeDataService) GetTypeList(ctx *gin.Context, baseId int, isShow int) []model.TypeListData {
	var isShowStr = ""
	if isShow == 1 {
		isShowStr = "and is_show=1 "
	} else if isShow == 0 {
		isShowStr = "and is_show=0 "
	} else {
		isShowStr = ""
	}

	db := database.GetDB()

	// 先获取所有的顶级(一级)分类
	sql := fmt.Sprintf("select `id`,`name`,IFNULL(`fid`,0),IFNULL(`fid_name`,''), `read_level`,`is_show` from bg_posts_type where fid=%d %s order by id ", baseId, isShowStr)

	rows, err := db.Raw(sql).Rows()
	if err != nil {
		zlog.Error(ctx, err)
		return []model.TypeListData{}
	}
	defer rows.Close()

	var wg sync.WaitGroup //声明一个等待组
	var types []model.TypeListData

	for rows.Next() {
		wg.Add(1)

		var t model.TypeListData
		var tIsShow int
		err := rows.Scan(&t.ID, &t.Name, &t.FID, &t.FIDName, &t.ReadLevel, &tIsShow)
		if err != nil {
			zlog.Error(ctx, err)
			continue
		}

		if tIsShow == 1 {
			t.IsShow = true
		} else {
			t.IsShow = false
		}

		// 获取文章数量
		postService := &PostDataService{}
		t.PostNum = postService.GetPostNum(ctx, t.ID, tIsShow)

		// 递归获取子分类
		t.Child = s.GetTypeList(ctx, t.ID, tIsShow)
		types = append(types, t)

		wg.Done()
	}

	wg.Wait() //塞到计数器的值为0

	return types
}

// GetSonIds 通过父级ID找所有下级的id
func (s *TypeDataService) GetSonIds(ctx *gin.Context, baseId int) []int {
	var ids []int
	db := database.GetDB()

	sql := fmt.Sprintf("select id from `bg_posts_type` where fid=%d ", baseId)

	rows, err := db.Raw(sql).Rows()
	if err != nil {
		zlog.Error(ctx, err)
		return []int{}
	}
	defer rows.Close()

	var id int
	for rows.Next() {
		err := rows.Scan(&id)
		if err != nil {
			zlog.Error(ctx, err)
			continue
		}
		ids = append(ids, id)
	}

	return ids
}

// GetPostTypeInfo 获取分类的名称
func (s *TypeDataService) GetPostTypeInfo(ctx *gin.Context, typeId int) model.TypeName {
	var dict map[int]model.TypeName

	if len(CacheTypesNames.Lists) == 0 || time.Now().Unix()-CacheTypesNames.CachedTime > 300 {
		db := database.GetDB()

		sql := "select id,name,fid,fid_name,read_level,is_show,add_time from `bg_posts_type` where 1 "

		rows, err := db.Raw(sql).Rows()
		if err != nil {
			zlog.Error(ctx, err)
			return model.TypeName{}
		}
		defer rows.Close()

		dict = make(map[int]model.TypeName)
		for rows.Next() {
			var d model.TypeName

			err := rows.Scan(&d.ID, &d.Name, &d.FID, &d.FName, &d.ReadLevel, &d.IsShow, &d.AddTime)
			if err != nil {
				zlog.Error(ctx, err)
				continue
			}
			dict[d.ID] = model.TypeName{ID: d.ID, Name: d.Name, FID: d.FID, FName: d.FName, ReadLevel: d.ReadLevel, IsShow: d.IsShow, AddTime: d.AddTime}
		}

		info := dict[typeId]
		CacheTypesNames.Lists = dict
		CacheTypesNames.CachedTime = time.Now().Unix()
		return info
	} else {
		dict = CacheTypesNames.Lists
		info := dict[typeId]
		return info
	}
}

// CacheTypesNames 分类名称缓存
var CacheTypesNames model.TypesNames

// ToHtml 生成HTML链接
func (s *TypeDataService) ToHtml(typeName model.TypeName, byAdmin bool) template.HTML {
	url := ""
	if byAdmin {
		url = "###"
	} else {
		url = "/search?"
	}
	str := ""
	if typeName.FID != 0 {
		str += fmt.Sprintf("<a href='%stype=%d'>%s</a> - ", url, typeName.FID, typeName.FName)
	}
	str += fmt.Sprintf("<a href='%stype=%d'>%s</a>", url, typeName.ID, typeName.Name)

	return template.HTML(str)
}

// checkAddFID 添加时检查FID
func (s *TypeDataService) checkAddFID(ctx *gin.Context, postType *model.TypeName, fid int) (bool, string) {
	if fid == 0 {
		return true, ""
	}

	postType.ID = fid
	err := s.getTypeNameInfo(ctx, postType)
	if err != nil {
		return false, "data not find"
	}

	if postType.FID != 0 {
		return false, "can not be add"
	}

	return true, ""
}

// checkAddName 名称检查
func (s *TypeDataService) checkAddName(ctx *gin.Context, postType *model.TypeName, name string, fid int) (bool, string) {
	if name == "" {
		return false, "name is empty"
	}

	if len(name) < 2 {
		return false, "name is too short"
	}

	if len(name) > 16 {
		return false, "name is too long"
	}

	db := database.GetDB()
	var num int64
	err := db.Table("bg_posts_type").Where("fid = ? AND name = ?", fid, name).Count(&num).Error
	if err != nil {
		return false, "database error"
	}

	if num >= 1 {
		return false, "name is repeat"
	}

	return true, ""
}

// getTypeNameInfo 获取分类信息
func (s *TypeDataService) getTypeNameInfo(ctx *gin.Context, typeName *model.TypeName) error {
	if typeName.ID <= 0 {
		return fmt.Errorf("id is null")
	}

	db := database.GetDB()
	sql := fmt.Sprintf("select `id`,`name`,`fid`,`fid_name`,`read_level`,`is_show`,`add_time` from `bg_posts_type` where id=%d", typeName.ID)

	err := db.Raw(sql).Row().Scan(&typeName.ID, &typeName.Name, &typeName.FID, &typeName.FName, &typeName.ReadLevel, &typeName.IsShow, &typeName.AddTime)
	if err != nil {
		return err
	}

	return nil
}

// GetTypeName 获取名称
func (s *TypeDataService) GetTypeName(ctx *gin.Context, id int) string {
	var typeName model.TypeName
	db := database.GetDB()

	if err := db.Where("id = ?", id).First(&typeName).Error; err != nil {
		return ""
	}

	return typeName.Name
}

// GetTypeNameByFID 根据父级ID获取类型名称
func (s *TypeDataService) GetTypeNameByFID(ctx *gin.Context, fid int) string {
	var typeName model.TypeName
	db := database.GetDB()

	if err := db.Where("id = ?", fid).First(&typeName).Error; err != nil {
		return ""
	}

	return typeName.Name
}
